/**
 * 
 */
package com.mobilottery.server;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;


/*
Stores lottery game details
 */
@Entity
@Table(name = "Game")
public class Game {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(name = "GAME_ID")
    private Long externalId;
    @Column(name = "DESCRIPTION")
    private String description;
    @Column(name = "PARTICIPATION_COST")
    private Float participationCost;
    @Column(name = "MAX_PRIZE")
    private Float maxPrize;
    @Column(name = "OPEN_DATE")
    @Temporal(TemporalType.TIMESTAMP)
    private Date openDate;
    @Column(name = "CLOSE_DATE")
    @Temporal(TemporalType.TIMESTAMP)
    private Date closeDate;
    @Column(name = "RESULT_DATE")
    @Temporal(TemporalType.TIMESTAMP)
    private Date resultDate;
    @Column(name = "TOTAL_WININGS")
    private Long totalWinings;
    @Column(name = "WINING_NUMBERS_RAW")
    private String winningNumbersRaw;
    @Transient
    private Set<Long> winingNumbers;
/*    @OneToMany(mappedBy = "game", cascade = CascadeType.ALL)
    private List<GameParticipation> gameParticipations = new ArrayList<GameParticipation>();
  */
    
    enum GameStatus
    {
    	Scheduled,
    	Active,
    	Closed,
    	Raffling,
    	Finished
    };

    public Game() {
    }

    public Game(Long externalId, String description, Float participationCost, Float maxPrize, Date openDate, Date closeDate, Date resultDate,
            Long totalWinings, String winningNumbersRaw, Set<Long> winingNumbers) {
        this.externalId = externalId;
        this.description = description;
        this.participationCost = participationCost;
        this.maxPrize = maxPrize;
        this.openDate = openDate;
        this.closeDate = closeDate;
        this.resultDate = resultDate;
        this.totalWinings = totalWinings;
        this.winningNumbersRaw = winningNumbersRaw;
        this.winingNumbers = new TreeSet<Long>(winingNumbers);
    }

    public Game(Long externalId, String description, Float participationCost, Float maxPrize, Date openDate, Date closeDate, Date resultDate) {
        this.externalId = externalId;
        this.description = description;
        this.participationCost = participationCost;
        this.maxPrize = maxPrize;
        this.openDate = openDate;
        this.closeDate = closeDate;
        this.resultDate = resultDate;
    }

    public Long getExternalId() {
        return externalId;
    }

    public Date getCloseDate() {
        return closeDate;
    }

    public String getDescription() {
        return description;
    }

    public Long getId() {
        return id;
    }

    public Date getOpenDate() {
        return openDate;
    }

    public Float getParticipationCost() {
        return participationCost;
    }

    public Date getResultDate() {
        return resultDate;
    }

    /**
     * Returns the string containing comma delimitied winninnng numbers  
     * @return numbers string
     */
    public String getWinningNumbersRaw() 
    {
    	//if winning numbers was set and no raw string representing them, rebuild the list string
        if(winingNumbers!=null && (winningNumbersRaw== null || winningNumbersRaw.isEmpty())) 
        {
            int numIndex = 0;
            winningNumbersRaw = "";
            for (Long winingNumber : this.winingNumbers) {
                this.winningNumbersRaw += String.valueOf(winingNumber.longValue());
                if (numIndex<winingNumbers.size()-1) 
                {
                    winningNumbersRaw += ",";
                }
                numIndex++;
            }
        }
        return winningNumbersRaw;
    }
    
    /**
     * Sets the string containing comma delimitied numbers
     * @param winningNumbersRaw
     */
    public void setwinningNumbersRaw(String winningNumbersRaw) {
        this.winningNumbersRaw = winningNumbersRaw;
    }    

    public Long getTotalWinings() {
        return totalWinings;
    }

    public Set<Long> getWiningNumbers() 
    {
    	//if no winning numbers list was build yet
        if (winingNumbers == null) {        	
            String winningNumbersRawStr = getWinningNumbersRaw();
            winingNumbers = new TreeSet<Long>();
            //if there is a string containing numbers, build the list from it
            if (winningNumbersRawStr != null && !winningNumbersRawStr.isEmpty()) 
            {
                StringTokenizer tk = new StringTokenizer(winningNumbersRawStr, ",");
                while (tk.hasMoreTokens()) {
                    winingNumbers.add(Long.parseLong(tk.nextToken()));
                }
            }
        }
        return winingNumbers;
    }
    
    public void setWiningNumbers(Set<Long> winingNumbers) {
        this.winingNumbers = new TreeSet<Long>(winingNumbers);
        //reset and rebuild raw string
        winningNumbersRaw = null;
        getWinningNumbersRaw();
    }    

    
    public List<GameParticipation> getGameParticipations() {
        String hql = "select g from GameParticipation as g where g.game.id = :gameId order by g.id desc";
        Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("gameId", getId());
        return PersistenceManager.getInstance().selectParamQuery(hql, parameters);
    }
    
    public void setCloseDate(Date closeDate) {
        this.closeDate = closeDate;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setOpenDate(Date openDate) {
        this.openDate = openDate;
    }

    public void setParticipationCost(Float participationCost) {
        this.participationCost = participationCost;
    }

    public void setResultDate(Date resultDate) {
        this.resultDate = resultDate;
    }

    public void setTotalWinings(Long totalWinings) {
        this.totalWinings = totalWinings;
    }

    /*public void setGameParticipations(List<GameParticipation> gameParticipations) {
        this.gameParticipations = gameParticipations;
    }*/

    public void setExternalId(Long externalId) {
        this.externalId = externalId;
    }

	public Float getMaxPrize() {
		return maxPrize;
	}

	public void setMaxPrize(Float maxPrize) {
		this.maxPrize = maxPrize;
	}
	
	@Transient
	public GameStatus getStatus()
	{		
		Date now = new Date();
		if(getWinningNumbersRaw()!=null) 
			return GameStatus.Finished;
		if(getResultDate().compareTo(now)<=0)
			return GameStatus.Raffling;			
		return getCloseDate().compareTo(now)<=0 ? GameStatus.Closed :
				(getOpenDate().compareTo(now)<=0 ? GameStatus.Active : GameStatus.Scheduled);
	}
	
	public boolean isGameFinished() {
		if( getStatus() == GameStatus.Finished)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	public boolean isGameActive() {
		if( getStatus() == GameStatus.Active)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	public boolean isGameClosed() {
		if( getStatus() == GameStatus.Closed)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
}
